package idv.cjcat.pyronova.nodes {
	import flash.utils.Dictionary;
	import idv.cjcat.pyronova.render.RenderVisitor;
	
	public class SortedGroup extends Group {
		
		public function SortedGroup(...children) {
			super(children);
		}
		
		
		//children management
		//------------------------------------------------------------------------------------------------
		
		override public function add(child:Node):void {
			if (_childrenIndicies[child] !== undefined) return;
			
			//remove from original parent
			if (child._parent) child._parent.remove(child);
			
			//expand vector if full
			_children[_fistEmptyIndex] = child;
			_childrenIndicies[child] = _fistEmptyIndex;
			if (++_fistEmptyIndex == _children.length) _children.length <<= 1;
			
			//listen for priority change
			child.onPriorityChange.add(invalidateChildrenPriority);
			
			//invalidate children priority
			_childrenPriorityDirty = true;
		}
		
		override public function remove(child:Node):void {
			if (_childrenIndicies[child] !== undefined) {
				
				//null parent
				child._parent = null;
				
				//remove from vector
				var index:int = _childrenIndicies[child];
				_children[index] = _children[--_fistEmptyIndex];
				_children[_fistEmptyIndex] = null;
				delete _childrenIndicies[child];
				
				//unlisten for priority change
				child.onPriorityChange.remove(invalidateChildrenPriority);
				
				//invalidate children priority
				_childrenPriorityDirty = true;
			}
		}
		
		override public function clear():void {
			var child:Node;
			for (var i:int = 0; i < _fistEmptyIndex; ++i) {
				child = _children[i];
				
				//null parent
				child._parent = null;
				
				//clear record
				delete _childrenIndicies[child];
				
				//unlisten for priority change
				child.onPriorityChange.remove(invalidateChildrenPriority);
				
				//empty vector element
				_children[i] = null;
			}
			
			_fistEmptyIndex = 0;
			_childrenPriorityDirty = false;
		}
		
		//------------------------------------------------------------------------------------------------
		//end of children management
		
		
		//children visiting
		//------------------------------------------------------------------------------------------------
		
		private var child:Node;
		private var _childrenPriorityDirty:Boolean = false;
		override public function render(visitor:RenderVisitor):void {
			
			//sort if children priority is dirty
			if (_childrenPriorityDirty) {
				_children.sort(childrenPrioritySorter);
				_childrenPriorityDirty = false;
			}
			
			visitor.pushMatrix(matrix());
			
			for (var i:int = 0; i < _fistEmptyIndex; ++i) {
				child = _children[i];
				
				//update index dictionary
				_childrenIndicies[child] = i;
				
				//visit child
				child.render(visitor);
			}
			
			visitor.popMatrix();
		}
		
		//------------------------------------------------------------------------------------------------
		//end of children visiting
		
		
		//priority sorting
		//------------------------------------------------------------------------------------------------
		
		private function invalidateChildrenPriority(child:Node = null):void {
			_childrenPriorityDirty = false;
		}
		
		private function childrenPrioritySorter(obj1:Node, obj2:Node):Number {
			if (obj1) {
				if (obj2) {
					if (obj1._priority == obj2._priority) {
						return _childrenIndicies[obj1] - _childrenIndicies[obj2];
					} else {
						return obj2._priority - obj1._priority;
					}
				} else {
					return -1;
				}
			} else {
				if (obj2) {
					return 1;
				} else {
					return 0;
				}
			}
		}
		
		//------------------------------------------------------------------------------------------------
		//end of priority sorting
	}
}